﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic.Entities;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Analytics.UI.Common.Wizard;
using DiscoveryLogic.Common.Utilities;
using MessageBox=System.Windows.MessageBox;
using TableColumn=DiscoveryLogic.Common.Utilities.TableColumn;
using UserControl=System.Windows.Controls.UserControl;

namespace DiscoveryLogic.Analytics.Modules.LinkRules
{
    /// <summary>
    /// Interaction logic for LinkRuleTgtEntityFieldMappings.xaml
    /// </summary>
    public partial class LinkRuleTgtEntityFieldMappings : UserControl, IWizardPageBase 
    {
        private Wizard _Owner;

        public LinkRuleTgtEntityFieldMappings()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.cboTgtEntityType.Items.Clear();
            foreach (EntityType entityType in Enum.GetValues(typeof(EntityType)))
            {
                this.cboTgtEntityType.Items.Add(entityType.ToString());
            }

            EntityRelationRule rule =
                (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];
            this.cboTgtEntityType.Text = rule.TgtEntityType.ToString();
        }

        private void cboTgtEntityType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!this.IsInitialized)
                return;

            EntityRelationRule rule =
                (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];
            TableColumn[] tgtCols = this.GetSqlOutput(rule);
            if (tgtCols != null && tgtCols.Length > 0 && this.cboTgtEntityType.SelectedIndex >= 0)
            {
                EntityType entityType =
                    (EntityType)Enum.Parse(
                                     typeof(EntityType),
                                     this.cboTgtEntityType.SelectedItem.ToString());
                this.dvTgtFieldMappings.Rows.Clear();
                PropertyInfo[] props = EntityTypeUtil.GetProperties(entityType);
                this.dvTgtFieldMappings.Rows.Clear();
                this.cboTimeStampField.Items.Clear();
                this.cboTimeStampField.Items.Clear();
                foreach (TableColumn tgtCol in tgtCols)
                {
                    this.cboTimeStampField.Items.Add(tgtCol.ColumnName);
                }
                if(!string.IsNullOrEmpty(rule.TimeStampField))
                    this.cboTimeStampField.SelectedValue = rule.TimeStampField;
                
                foreach(PropertyInfo prop in props)
                {
                    if(!prop.CanRead || !prop.CanWrite)
                        continue;
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewTextBoxCell cellEntityField=new DataGridViewTextBoxCell();
                    cellEntityField.Value = prop.Name;
                    dr.Cells.Add(cellEntityField);
                    DataGridViewComboBoxCell cellTgtField=new DataGridViewComboBoxCell();
                    foreach(TableColumn col in tgtCols)
                    {
                        cellTgtField.Items.Add(col.ColumnName);
                    }
                    if(rule.OutputFieldNameMappings !=null && 
                        rule.OutputFieldNameMappings.ContainsKey(prop.Name))
                    {
                        cellTgtField.Value = rule.OutputFieldNameMappings[prop.Name];
                    }
                    dr.Cells.Add(cellTgtField);
                    this.dvTgtFieldMappings.Rows.Add(dr);
                }
                this.dvTgtFieldMappings.Refresh();
            }
        }

        #region Implementation of IWizardPageBase

        public event OnBeforeMoveToNext BeforeMoveToNext;
        public event OnBeforeDisplay BeforeDisplay;
        private IWizardPageBase _PrevPage;
        public IWizardPageBase PrevPage
        {
            get
            {
                return _PrevPage;
            }
            set
            {
                _PrevPage = value;
            }
        }

        private IWizardPageBase _NextPage;
        public IWizardPageBase NextPage
        {
            get
            {
                return _NextPage;
            }
            set
            {
                _NextPage = value;
            }
        }

        private string _Title = "Target fields";
        public string Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
            }
        }

        private string _Desc = "Specify how target fields is retrieved from sql query results";
        public string Description
        {
            get
            {
                return _Desc;
            }
            set
            {
                _Desc = value;
            }
        }

        public void Init(Wizard owner)
        {
            this._Owner = owner;
        }

        public bool MoveNextPage()
        {
            if(this.cboTgtEntityType.SelectedIndex<0)
                return false;
            try
            {
                EntityRelationRule rule =
                    (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];
                if (this.cboTimeStampField.SelectedIndex >= 0)
                    rule.TimeStampField = this.cboTimeStampField.SelectedItem.ToString();

                rule.TgtEntityType =
                    (EntityType) Enum.Parse(typeof (EntityType), this.cboTgtEntityType.SelectedItem.ToString());
                rule.OutputFieldNameMappings = new Dictionary<string, string>();
                foreach (DataGridViewRow dr in this.dvTgtFieldMappings.Rows)
                {
                    if (!dr.IsNewRow && dr.Cells[0].Value != null && dr.Cells[1].Value != null)
                    {
                        string propName = dr.Cells[0].Value.ToString();
                        string colName = dr.Cells[1].Value.ToString();
                        rule.OutputFieldNameMappings.Add(propName, colName);
                    }
                }
                if(this.BeforeMoveToNext !=null)
                    this.BeforeMoveToNext(new WizardPageNavigationEventArgs(this._Owner, false));
                return true;
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                MessageBox.Show(ex.Message);
                return false;
            }
        }

        public void MovePrevPage()
        {
            throw new System.NotImplementedException();
        }

        #endregion

        #region sql output
        private DataTable GetSrcEntitySetData(EntityRelationRule rule)
        {
            try
            {
                if (rule.SrcDataFrom == SampleDataSourceType.EntityDataSet)
                {
                    List<EntityBase> entities = DataSetManager.ReadEntitySetData(
                        rule.SrcEntityType, rule.SrcEntitySetName);
                    return EntityManager.ToTable(rule.SrcEntityType, entities);
                }
                else
                {
                    List<EntityBase> entities = new List<EntityBase>();
                    Network network = Network.Read(rule.NetworkName);
                    foreach (EntityBase entity in network.Records)
                    {
                        if (entity.EntityType == rule.SrcEntityType && entity.PKValue() == rule.SrcKey)
                        {
                            entities.Add(entity);
                            break;
                        }
                    }
                    return EntityManager.ToTable(rule.SrcEntityType, entities);
                }
            }
            catch(Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                MessageBox.Show(ex.Message);
                return null;
            }
        }

        private TableColumn[] GetSqlOutput(EntityRelationRule rule)
        {
            DataTable dtSrcSet = this.GetSrcEntitySetData(rule);
            if(dtSrcSet==null)
                return null;
            string sql = rule.Sql;
            Regex paramRegex = new Regex(@"@([^\s=,\)]+)", RegexOptions.IgnoreCase);
            Match paramMatch = paramRegex.Match(rule.Sql);
            while (paramMatch.Success)
            {
                string paramName = paramMatch.Groups[1].Value;
                if (rule.SqlParameters.ContainsKey(paramName))
                {
                    string propName = rule.SqlParameters[paramName];
                    string srcFieldName = rule.FieldNameMappings[propName];
                    SqlDbType dbType = rule.ParameterTypes[paramName];
                    SimpleDataType dbType2 = SimpleDataTypeUtil.ToSimpleDataType(dbType);
                    object fieldValue = dtSrcSet.Rows[0][srcFieldName];
                    fieldValue = SimpleDataTypeUtil.ReadDbValue(dbType2, fieldValue);

                    if (fieldValue == null)
                    {
                        sql = sql.Replace("@" + paramName, "null");
                    }
                    //else if (rule.FieldTransformations.ContainsKey(srcFieldName))
                    //{
                    //    object transformedValue = fieldValue;
                    //    string sqlValue = FieldDataType.ToMssqlDataValue(dbType, transformedValue.ToString());
                    //    sql = sql.Replace("@" + paramName, sqlValue);
                    //}
                    else
                    {
                        string sqlValue = FieldDataType.ToMssqlDataValue(dbType, fieldValue.ToString());
                        sql = sql.Replace("@" + paramName, sqlValue);
                    }
                }

                paramMatch = paramMatch.NextMatch();
            }

            this.dvTgtFieldMappings.Rows.Clear();
            TableColumn[] cols = DbUtil.GetTableColumns(
                rule.DbProvider,
                rule.ConnStr, sql);
            return cols;

        }
        #endregion

        private void cboTimeStampField_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            
        }
    }
}
